import re  # 新增正则模块导入
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import pdfplumber
import pandas as pd
from pathlib import Path
# from pdf_to_excel import process_data  # 删除这行导入语句

class PDFTableApp:
    def __init__(self, master):
        self.master = master
        self.master.title("PDF表格提取工具-琪睿科技v1.4")
        self.selected_files = []  # 新增文件列表存储

        # 创建界面组件
        self.create_widgets()
        self.current_data = None

    def create_widgets(self):
        # 顶部按钮区域
        control_frame = tk.Frame(self.master)
        control_frame.pack(pady=10)
        
        self.btn_select = ttk.Button(control_frame, text="选择PDF文件", command=self.select_files)
        self.btn_select.pack(side=tk.LEFT, padx=5)
        
        self.btn_parse = ttk.Button(control_frame, text="解析表格", command=self.parse_files)
        self.btn_parse.pack(side=tk.LEFT, padx=5)
        
        self.btn_export = ttk.Button(control_frame, text="导出Excel", command=self.export_excel)
        self.btn_export.pack(side=tk.LEFT, padx=5)

        # 表格展示区域
        tree_frame = tk.Frame(self.master)
        tree_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 配置Treeview样式（新增代码）
        style = ttk.Style()
        style.configure("Treeview", rowheight=35)  # 设置行高为35像素

        # 修改Treeview初始化配置
        self.tree = ttk.Treeview(tree_frame, show='headings', style="Treeview", selectmode="extended")  # 添加多选模式
        vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        
        # 使用grid布局管理器
        self.tree.grid(row=0, column=0, sticky='nsew')
        vsb.grid(row=0, column=1, sticky='ns')
        hsb.grid(row=1, column=0, sticky='ew')
        
        # 配置自适应缩放
        tree_frame.grid_rowconfigure(0, weight=1)
        tree_frame.grid_columnconfigure(0, weight=1)

    def select_files(self):
        self.selected_files = filedialog.askopenfilenames(
            filetypes=[("PDF文件", "*.pdf")],
            title="选择要解析的PDF文件"
        )
        
    def parse_files(self):
        try:
            combined_df = pd.DataFrame()
            for pdf_path in self.selected_files:
                with pdfplumber.open(pdf_path) as pdf:
                    # 提取当前PDF的供货单号（优先封面页）
                    supply_order = None
                    ht_order = None
                    for page in pdf.pages:
                        text = page.extract_text()
                        
                        match = re.search(r'采购合同编号[:：]?\s*(SG\w{17})', text)
                        if match:
                            ht_order = match.group(1).strip()
                        match = re.search(r'供货单号[:：]?\s*([A-Z0-9-]{8,})', text)
                        if match:
                            supply_order = match.group(1).strip()
                            break
                    
                    # 处理当前PDF的表格数据
                    # 修改表格处理逻辑
                    headers = []
                    pdf_data = []
                    for page_idx, page in enumerate(pdf.pages):
                        table = page.extract_table({'vertical_strategy': 'lines', 'horizontal_strategy': 'lines'})
                        if table:
                            print(f"第{page_idx+1}页: 提取到表格，共{len(table)}行")
                            print(f"  表头: {table[0]}")
                            
                            print(f"  上一页数据行数: {len(pdf_data)}")
                            print(f"  上一页最后数据行: {pdf_data[-1] if pdf_data else '无'}")
                            if table[0][0]=="":
                                # 合并当前页表头与上一页最后数据行
                                if pdf_data:
                                    last_row = pdf_data[-1]
                                    # 合并逻辑：将当前页表头合并到上一页最后一条数据
                                    #遍历 table[0]后续每列，都追加到 last_row[2]
                                    for col_idx in range(2, len(table[0])):
                                        last_row[col_idx] = last_row[col_idx] + table[0][col_idx]  # 合并当前页表头（假设第一列是序号，不合并）
                                    print(f"  合并表头到上一页最后数据行: {last_row}")
                            if len(table) > 1:
                                print(f"  数据行数: {len(table)-1}")
                                for row_idx, row in enumerate(table[1:min(3, len(table))]):  # 只打印前3行数据
                                    print(f"    第{row_idx+1}行: {row}")
                                    if "总" in row[0]  :
                                        table.remove(row)
                            
                            # 保存首个有效表头
                            if not headers and len(table) > 0:
                                headers = table[0]
                                print(f"  使用表头: {headers}")
                            # 添加数据行（排除表头）
                            if len(table) > 1:
                                # 特别处理第二页及以后的表头数据合并问题（Terminal#845-856）
                                if page_idx > 0 and len(table) > 1:
                                    # 如果是第二页及以后，检查是否存在表头延续数据
                                    first_data_row = table[1]
                                    # 检查第一行是否为分页延续数据（通常是空序号但有内容）
                                    if (len(first_data_row) > 0 and 
                                        (not first_data_row[0] or not str(first_data_row[0]).strip()) and 
                                        any(cell and str(cell).strip() for cell in first_data_row[1:])):
                                        print(f"  检测到第{page_idx+1}页的分页延续数据，将其合并到上一页最后一条数据")
                                        # 将这行数据合并到上一页的最后一条数据中
                                        if pdf_data:
                                            last_row = pdf_data[-1]
                                            # 合并逻辑：将分页延续数据合并到上一页最后一条数据
                                            for i in range(min(len(last_row), len(first_data_row))):
                                                if first_data_row[i] and str(first_data_row[i]).strip():
                                                    if last_row[i] and str(last_row[i]).strip():
                                                        # 如果两行都有内容，合并它们
                                                        last_row[i] = str(last_row[i]).strip() + ' ' + str(first_data_row[i]).strip()
                                                    else:
                                                        # 如果上一行该列为空，直接使用当前行的内容
                                                        last_row[i] = str(first_data_row[i]).strip()
                                            print(f"  合并后最后一条数据: {last_row}")
                                            # 添加剩余的数据行（排除已处理的第一行）
                                            pdf_data.extend(table[2:])
                                        else:
                                            # 如果还没有数据，正常添加所有行
                                            pdf_data.extend(table[1:])
                                    else:
                                        # 正常情况，添加所有数据行
                                        pdf_data.extend(table[1:])
                                else:
                                    # 第一页或其他情况，正常添加数据行
                                    pdf_data.extend(table[1:])
                                print(f"  累计数据行数: {len(pdf_data)}")
                        else:
                            print(f"第{page_idx+1}页: 未提取到表格")
                    
                    if pdf_data:
                        # 使用统一表头重构数据
                        #判断 如tables每行中第一列含有总字 则删除该行
                        for table in pdf_data:
                            print("table[0]",table[0])
                            if '总' in table[0]:
                                print("table[0]table",table)
                                pdf_data.remove(table)
                        df = self.process_data([headers] + pdf_data)  
                        df.insert(1,'合同编号', ht_order or f'未提取_{Path(pdf_path).stem[:5]}')
                        df.insert(2, '供货单号', supply_order or f'未提取_{Path(pdf_path).stem[:5]}')
                        combined_df = pd.concat([combined_df, df], ignore_index=True)

            if not combined_df.empty:
                self.current_data = combined_df
                self.display_data(combined_df)
                messagebox.showinfo("成功", f"解析完成！共处理{len(self.selected_files)}个文件")
            else:
                messagebox.showwarning("提示", "未找到有效表格数据")
                
        except Exception as e:
            messagebox.showerror("错误", f"解析失败: {str(e)}")

    # 新增处理函数
    def process_data(self, tables):
        """独立的数据处理方法"""
        if not tables:
            return pd.DataFrame()
            
        header = tables[0]
        data = tables[1:]  # 修复：保留所有数据行，不再丢弃最后一行
        # 改进分页数据合并逻辑
        merged_data = []
        prev_row = None
        
        # 查找项目名称列的索引
        project_name_idx = -1
        serial_idx = 0  # 默认序号列为第一列
        for i, col in enumerate(header):
            if '项目名称' in col:
                project_name_idx = i
            elif '序号' in col:
                serial_idx = i
        
        # 用于跟踪上一行是否为有效数据行
        prev_is_valid_row = False
        
        for row_idx, row in enumerate(data):
            # 确保row是列表格式
            if not isinstance(row, list):
                row = list(row)
            
            current_serial = row[serial_idx] if len(row) > serial_idx else ''
            # 增强的分页行检测逻辑
            is_pagination_row = False
            
            # 情况1：无序号但有内容的行通常是分页行
            if not current_serial and any(cell and str(cell).strip() for cell in row if cell != current_serial):
                is_pagination_row = True
                print(f"检测到分页行(情况1): 行{row_idx}, 序号='{current_serial}', 内容={row}")
            # 情况2：项目名称列有内容的行（可能是项目名称延续到下一页）
            elif project_name_idx >= 0 and len(row) > project_name_idx and row[project_name_idx] and prev_row and prev_is_valid_row:
                # 如果该项目名称列有内容，而序号列无内容，则认为是分页行
                if not current_serial:
                    is_pagination_row = True
                    print(f"检测到分页行(情况2): 行{row_idx}, 项目名称='{row[project_name_idx]}'")
            # 情况3：序号列有数字但项目名称列为空的行（可能是项目名称延续到下一页）
            elif (current_serial and 
                  str(current_serial).isdigit() and 
                  project_name_idx >= 0 and 
                  len(row) > project_name_idx and 
                  not row[project_name_idx] and 
                  prev_row and 
                  prev_is_valid_row):
                is_pagination_row = True
                print(f"检测到分页行(情况3): 行{row_idx}, 序号='{current_serial}', 项目名称='{row[project_name_idx]}'")
            # 情况4：序号是连续数字的行（可能是数据行跨页）
            elif (current_serial and str(current_serial).isdigit() and 
                  prev_row and prev_is_valid_row and 
                  project_name_idx >= 0 and len(prev_row) > project_name_idx and not prev_row[project_name_idx]):
                # 如果前一行是有效数据行但项目名称为空，当前行有序号和项目名称，则可能是跨页数据
                if (len(row) > project_name_idx and row[project_name_idx] and 
                    str(row[project_name_idx]).strip()):
                    is_pagination_row = True
                    print(f"检测到分页行(情况4): 行{row_idx}, 序号='{current_serial}', 项目名称='{row[project_name_idx]}'")
            # 情况5：处理像Terminal#853-856这样第三列内容是上一页数据延续的情况
            # 只有当前行没有有效序号且某列包含换行符内容时，才可能是分页行
            elif (not current_serial and 
                  prev_row and prev_is_valid_row):
                # 检查每一列是否可能是上一页数据的延续
                for col_idx, cell_value in enumerate(row):
                    if (cell_value and str(cell_value).strip() and 
                        '\n' in str(cell_value) and 
                        len(str(cell_value).split('\n')) > 1 and
                        col_idx != serial_idx):  # 排除序号列
                        # 如果该列内容包含换行符且不是序号列，则可能是上一页数据延续
                        is_pagination_row = True
                        print(f"检测到分页行(情况5): 行{row_idx}, 列{col_idx} 包含跨页数据: '{cell_value}'")
                        break
            
            # 判断当前行是否为有效数据行（有有效序号）
            is_valid_row = bool(current_serial and str(current_serial).isdigit())
            
            if is_pagination_row and prev_row:
                # 增强合并逻辑，特别处理项目名称字段和其他有内容的字段
                for i in range(len(row)):
                    if i < len(prev_row) and row[i]:  # 确保索引有效且内容非空
                        # 对于项目名称列，总是合并（即使是分页行也有可能有部分内容）
                        if i == project_name_idx and row[i]:
                            if prev_row[i]:  # 前一行该列有内容，进行合并
                                prev_row[i] = str(prev_row[i]).strip() + ' ' + str(row[i]).strip()
                            else:  # 前一行该列无内容，直接赋值
                                prev_row[i] = str(row[i]).strip()
                            print(f"合并项目名称: 行{row_idx} '{row[i]}' -> '{prev_row[i]}'")
                        # 对于其他列，只有在特定条件下才合并
                        elif row[i] and str(row[i]).strip():
                            # 特别处理包含换行符的内容（如Terminal#853-856的情况）
                            cell_content = str(row[i]).strip()
                            # 如果内容包含换行符，先处理换行符
                            if '\n' in cell_content:
                                # 将换行符替换为空格，使内容更易读
                                cell_content = ' '.join(cell_content.split('\n'))
                            
                            # 如果前一行该列已经有内容，则追加
                            if prev_row[i] and str(prev_row[i]).strip():
                                prev_row[i] = str(prev_row[i]).strip() + ' ' + cell_content
                            else:  # 前一行该列无内容，直接赋值
                                prev_row[i] = cell_content
            else:
                if prev_row:
                    print(f"添加完整行{len(merged_data)+1}: {prev_row}")
                    merged_data.append(prev_row)
                prev_row = list(row) if row else []
                prev_is_valid_row = is_valid_row
                
        # 添加最后一行
        if prev_row:
            print(f"添加最后一行: {prev_row}")
            merged_data.append(prev_row)
            
        df = pd.DataFrame(merged_data, columns=header)
        print("tablestables",tables)
        #判断 如tables每行中第一列含有总字 则删除该行
        for table in tables:
            print("table[0]",table[0])
            if '总' in table[0]:
                print("table[0]table",table)
                tables.remove(table)

        # 列名清理（严格处理换行符）
        df.columns = df.columns.str.replace(r'\n', '', regex=True)
        
        # 增强字段内容清理（处理换行符和连续空格）
        text_columns = ['收货单位', '项目名称', '货物名称','规格型号', '项目单位/收货方']
        for col in text_columns:
            if col in df.columns:
                print(f"清理字段 '{col}' 的内容")
                # 使用正则表达式替换换行符和连续空格为单个空格
                df[col] = df[col].astype(str).str.replace(r'[\n\s]+', ' ', regex=True).str.strip()
                # 进一步清理字段中字与字之间的多余空格
                df[col] = df[col].str.replace(r'(?<=\S)\s+(?=\S)', '', regex=True)  # 移除汉字/字符之间的单个空格
        
        # 字段映射
        print("执行字段映射前的列名:", df.columns.tolist())
        df = df.rename(columns={
            '项目单位/收货方': '收货单位',
            '分项价(不含税）': '合同金额'
        }, errors='ignore')
        print("执行字段映射后的列名:", df.columns.tolist())
        
        # 处理订单编号，放宽序号验证，保留所有有效数据
        if '序号' in df.columns:
            print("处理订单编号...")
            # 标记有效序号行（修复正则表达式）
            valid_serial_rows = df['序号'].notna() & df['序号'].astype(str).str.match(r'^\d+$')
            
            # 标记有实际数据的行（避免删除有用的分页行）
            has_meaningful_data = df.apply(lambda row: any(
                i != serial_idx and cell and str(cell).strip() and str(cell).strip() != 'nan'
                for i, cell in enumerate(row)
            ), axis=1)
            
            # 保留有效序号行和有意义数据的行
            df = df[valid_serial_rows | has_meaningful_data]
            
            # 为有效序号行生成订单编号
            if not df.empty:
                df['订单编号'] = ''
                # 只对有效序号行生成标准订单编号
                if valid_serial_rows.any():
                    df.loc[valid_serial_rows, '订单编号'] = 'XD' + df.loc[valid_serial_rows, '序号'].astype(str).str.zfill(6)
                
                # 为其他有数据的行生成临时编号
                temp_rows = (~valid_serial_rows) & has_meaningful_data
                if temp_rows.any():
                    temp_counter = 1
                    for idx in df[temp_rows].index:
                        df.loc[idx, '订单编号'] = f'TEMP_{temp_counter:06d}'
                        temp_counter += 1
        else:
            # 重新生成序号
            df = df.reset_index(drop=True)
            df['订单编号'] = 'XD' + (df.index + 1).astype(str).str.zfill(6)
            
        return df

    def display_data(self, df):
        """展示数据到表格"""
        if not hasattr(self, 'tree') or self.tree.winfo_exists() == 0:
            return
        
        # 清空现有数据
        self.tree.delete(*self.tree.get_children())
        
        # 动态获取列名（优先使用数据中的列）
        columns = df.columns.tolist() if not df.empty else []
        # 设置默认显示列（当数据为空时）
        default_columns = ['订单编号', '收货单位', '项目名称', '数量']
        columns = columns if columns else default_columns
        
        # 配置表格列（恢复固定列宽设置）
        self.tree["columns"] = columns
        for col in columns:
            self.tree.heading(col, text=col)
            # 项目名称列宽设为其他列的两倍
            col_width = 240 if col == '项目名称' else 120
            self.tree.column(col, width=col_width, anchor='w', stretch=True)
            
        # 强制更新布局
        self.master.update_idletasks()
        
        # 插入数据
        if not df.empty:
            for _, row in df.iterrows():
                print("row....",row)
                self.tree.insert("", "end", values=tuple(row.get(col, '') for col in columns))
            
        # 添加右键菜单
        self.tree.bind("<Button-3>", self.show_context_menu)
        self.context_menu = tk.Menu(self.master, tearoff=0)
        self.context_menu.add_command(label="复制", command=self.copy_selected_data)

    def copy_selected_data(self):
        """复制选中数据到剪贴板"""
        selected_items = self.tree.selection()
        if selected_items:
            # 获取所有列名（包括隐藏列）
            columns = self.tree["columns"]
            data = []
            for item in selected_items:
                # 获取完整数据记录
                item_data = self.tree.item(item)['values']
                # 转换为字符串并用制表符分隔
                data.append('\t'.join(map(str, item_data)))
            self.master.clipboard_clear()
            self.master.clipboard_append('\n'.join(data))
            
    def show_context_menu(self, event):
        """显示右键菜单"""
        self.context_menu.post(event.x_root, event.y_root)
        
    def export_excel(self):
        if self.current_data is not None and not self.current_data.empty:
            save_path = filedialog.asksaveasfilename(
                defaultextension=".xlsx",
                filetypes=[("Excel文件", "*.xlsx")]
            )
            if save_path:
                try:
                    self.current_data.to_excel(save_path, index=False)
                    messagebox.showinfo("成功", "导出完成！")
                except Exception as e:
                    messagebox.showerror("错误", f"导出失败: {str(e)}")
                    
if __name__ == "__main__":
    root = tk.Tk()
    root.state('zoomed')  # 添加窗口最大化设置
    app = PDFTableApp(root)
    root.mainloop()